﻿// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

namespace SketchFlow.SaveState.Interactions
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Windows;
	using System.Windows.Controls;
	using System.Windows.Interactivity;
	using Microsoft.Expression.Prototyping.Navigation;
	using Microsoft.Expression.Prototyping.Services;

	[TypeConstraint(typeof(UserControl))]
	public sealed class SaveVisualStateBehavior : Behavior<UserControl>
	{
		private static readonly Dictionary<string, object> dataStore = new Dictionary<string, object>();

		protected override void OnAttached()
		{
			base.OnAttached();
			this.AttachCore();
		}

		protected override void OnDetaching()
		{
			base.OnDetaching();
			this.DetachCore();
		}

		private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
		{
			this.PreserveState(this.LoadState);
		}

		private void AssociatedObject_Unloaded(object sender, RoutedEventArgs e)
		{
			this.DetachCore();
		}

		private void ActiveNavigationViewModel_CurrentScreenChanging(object sender, ScreenChangingEventArgs e)
		{
			this.PreserveState(this.SaveState);
		}

		private void PreserveState(Action<UserControl, VisualStateGroup, string> preserveStateAction)
		{
			UserControl screen = this.AssociatedObject;
			FrameworkElement content = screen.Content as FrameworkElement;

			IEnumerable<VisualStateGroup> groups = VisualStateManager.GetVisualStateGroups(content).OfType<VisualStateGroup>();
			foreach (VisualStateGroup group in groups)
			{
				string key = DependencyObjectHelper.GeneratePathString(screen, this.GetType().FullName, group.Name);
				if (string.IsNullOrEmpty(key))
					continue;

				preserveStateAction(screen, group, key);
			}
		}

		private void SaveState(UserControl screen, VisualStateGroup group, string key)
		{
			if (group.CurrentState == null)
			{
				return;
			}

			string value = group.CurrentState.Name;

			dataStore[key] = value;
		}

		private void LoadState(UserControl screen, VisualStateGroup group, string key)
		{
			if (!dataStore.ContainsKey(key))
			{
				return;
			}

			string value = dataStore[key] as string;

			if (screen == null || group.States == null || !group.States.OfType<VisualState>().Select(state => state.Name).Contains(value))
			{
				return;
			}

			VisualStateManager.GoToState(screen, value, false);
		}

		private void AttachCore()
		{
			this.AssociatedObject.Loaded += this.AssociatedObject_Loaded;
			this.AssociatedObject.Unloaded += this.AssociatedObject_Unloaded;
			PlayerContext.Instance.ActiveNavigationViewModel.CurrentScreenChanging += this.ActiveNavigationViewModel_CurrentScreenChanging;
		}

		private void DetachCore()
		{
			this.AssociatedObject.Loaded -= this.AssociatedObject_Loaded;
			this.AssociatedObject.Unloaded -= this.AssociatedObject_Unloaded;
			PlayerContext.Instance.ActiveNavigationViewModel.CurrentScreenChanging -= this.ActiveNavigationViewModel_CurrentScreenChanging;
		}
	}
}

